package com.billdowney.service.impl.auth;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.annotation.Resource;

import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import com.billdowney.annotation.AuthRoleAllowed;
import com.billdowney.dao.auth.AuthActionDao;
import com.billdowney.dao.auth.AuthRoleDao;
import com.billdowney.entity.auth.AuthAction;
import com.billdowney.entity.auth.AuthRole;
import com.billdowney.service.impl.base.BaseServiceImpl;
import com.billdowney.service.interfaces.auth.AuthManageService;
import com.billdowney.util.CommonUtil;
import com.billdowney.util.auth.AuthRoleConst;
import com.billdowney.util.auth.AuthRoleMaps;
import com.billdowney.util.auth.AuthUtil;

import io.swagger.annotations.ApiOperation;

/**
 * 权限管理业务接口实现
 * 
 * @author 超级小富翁 - BillDowney
 * @data 2017年8月19日 下午4:29:04
 */
@Service
public class AuthManageServiceImpl extends BaseServiceImpl<AuthActionDao, AuthAction, String>
		implements AuthManageService {

	@Value("${server.servlet.context-path}")
	private String projectName;
	@Autowired
	private AuthRoleDao authRoleDao;
	// 获取所有springMVC注册的url
	@Autowired
	private RequestMappingHandlerMapping mapping;
	@Autowired
	private AuthRoleMaps authRoleMaps;

	@Resource(type = AuthActionDao.class)
	@Override
	public void setDao(AuthActionDao dao) {
		super.dao = dao;
	}

	@Override
	public List<AuthAction> collectAllController() {
		List<AuthAction> data = new ArrayList<>();
		// 获取url与类和方法的对应信息
		Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
		for (Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
			RequestMappingInfo info = entry.getKey();
			HandlerMethod method = entry.getValue();
			// 获取匹配的url
			for (String url : info.getPatternsCondition().getPatterns()) {
				AuthAction action = new AuthAction();
				action.setUrl(url);
				action.setFilterUrl(AuthUtil.filterUrlPathVariable(action.getUrl()));
				action.setClassName(method.getMethod().getDeclaringClass().getName());
				action.setClassSimpleName(method.getMethod().getDeclaringClass().getSimpleName());
				action.setMethodName(method.getMethod().getName());
				// 获取请求方法
				String requestMethod = "";
				for (RequestMethod m : info.getMethodsCondition().getMethods()) {
					requestMethod += "," + m.toString();
				}
				action.setRequestMethod(requestMethod.replaceFirst(",", ""));
				// 获取swagger中的Api信息
				if (method.hasMethodAnnotation(ApiOperation.class)) {
					ApiOperation apiOperation = method.getMethodAnnotation(ApiOperation.class);
					action.setActionName(apiOperation.value());
					action.setDescription(apiOperation.notes());
				}
				action.setProjectName(projectName);
				// 配置角色
				AuthRole authRole = new AuthRole();
				authRole.setCreateDate(null);
				if (method.hasMethodAnnotation(AuthRoleAllowed.class)) {
					AuthRoleAllowed authRoleAllowed = method.getMethodAnnotation(AuthRoleAllowed.class);
					authRole.setRoleCode(authRoleAllowed.value());
				} else {
					authRole.setRoleCode(AuthRoleConst.NOT_CONFIG);
				}
				authRole.setRoleName(authRoleMaps.getString(authRole.getRoleCode()));
				action.setAuthRole(authRole);
				data.add(action);
			}
		}
		return data;
	}

	@Override
	public Map<String, List<AuthAction>> addAllController() {
		Map<String, List<AuthAction>> map = this.classifyRoleAuthAction();
		Map<String, AuthRole> roleMaps = new HashMap<>();
		// 先查询数据库是否有角色
		for (Entry<String, List<AuthAction>> entry : map.entrySet()) {
			AuthRole authRole = new AuthRole();
			authRole.setRoleCode(entry.getKey());
			Optional<AuthRole> authRoleData = authRoleDao.findOne(Example.of(authRole));
			if (authRoleData.isPresent()) {
				roleMaps.put(entry.getKey(), authRoleData.get());
			} else {
				authRole = entry.getValue().get(0).getAuthRole();
				authRole.setCreateDate(new Date());
				roleMaps.put(entry.getKey(), authRoleDao.save(authRole));
			}
		}
		// 保存对应角色关系的action
		for (Entry<String, List<AuthAction>> entry : map.entrySet()) {
			for (AuthAction authAction : entry.getValue()) {
				AuthAction action = new AuthAction();
				action.setUrl(authAction.getUrl());
				Optional<AuthAction> authRoleData = dao.findOne(Example.of(action));
				if (!authRoleData.isPresent()) {
					authAction.setAuthRole(roleMaps.get(entry.getKey()));
					dao.save(authAction);
				}
			}
		}
		return map;
	}

	@Override
	public Map<String, List<AuthAction>> classifyRoleAuthAction() {
		List<AuthAction> entities = this.collectAllController();
		Map<String, List<AuthAction>> map = new HashMap<String, List<AuthAction>>();
		for (AuthAction authAction : entities) {
			if (CommonUtil.isNotEmpty(authAction.getAuthRole())) {
				AuthRole role = authAction.getAuthRole();
				List<AuthAction> list;
				if (map.containsKey(role.getRoleCode())) {
					list = new ArrayList<>(map.get(role.getRoleCode()));
					list.add(authAction);
				} else {
					list = Arrays.asList(authAction);
				}
				map.put(role.getRoleCode(), list);
			}
		}
		return map;
	}

}
